#include <stdint.h>
#include "modbus_rtu.h"
#include "app_main.h"
// 计算 Modbus RTU CRC16
uint16_t modbus_rtu::modbus_crc16(uint8_t *buffer, int length)
{
    uint16_t crc = 0xFFFF;  // 初始值
    uint16_t poly = 0xA001; // 多项式 0x8005 的位反转

    for (int i = 0; i < length; i++)
    {
        crc ^= buffer[i];
        for (int j = 0; j < 8; j++)
        {
            if (crc & 0x0001)
            {
                crc = (crc >> 1) ^ poly;
            }
            else
            {
                crc >>= 1;
            }
        }
    }

    return crc;
}
modbus_rtu::modbus_rtu()
{
    modbus_rtu_category = zlog_get_category(ZLOG_CAG_MODBUS_RTU);
    assert(modbus_rtu_category != nullptr);
    modbus_rtu_thread = std::make_shared<std::thread>(&modbus_rtu::modbus_rtu_thread_func, this);
    assert(modbus_rtu_thread != nullptr);
    modbus_rtu_serial_app = std::make_shared<serial_app>();
    assert(modbus_rtu_serial_app != nullptr);
    modbus_rtu_serial_app->open_serial(MODBUS_RTU_TTY_NAME);
    zlog_info(modbus_rtu_category, "modbus_rtu init success");
}
modbus_rtu::~modbus_rtu()
{
}

uint32_t modbus_rtu::create_modbus_rtu_packet_rsp_status(std::vector<uint8_t> &packet)
{
    packet.clear();
    vector<uint8_t> data;
    msb_push_u16_to_array(data, static_cast<uint16_t>(PUSH_DATA_TYPE::BackgroundStatus));
    uint32_t *u32ptr = get_dev_data_ptr()->reg_rsp_status;
    for (int i = 0; i < get_dev_data_ptr()->reg_rsp_num; i++)
    {
        msb_push_u32_to_array(data, u32ptr[i]);
    }
    // 1.addr
    msb_push_u8_to_array(packet, modbus_rtu_slave_addr);
    // 2.op
    msb_push_u8_to_array(packet, OPS::READ);
    // 3. data len
    msb_push_u8_to_array(packet, static_cast<uint16_t>(data.size()));
    packet.insert(packet.end(), data.begin(), data.end());
    // 4.crc
    uint16_t crc = modbus_crc16(packet.data(), packet.size());
    lsb_push_u16_to_array(packet, crc);

    return 0;
}
uint32_t modbus_rtu::create_modbus_rtu_packet_rsp_data(vector<uint8_t> &packet, const PUSH_DATA_TYPE type)
{
    packet.clear();
    vector<uint8_t> data;
    msb_push_u16_to_array(data, static_cast<uint16_t>(type));
    float *floatptr = nullptr;
    if (type == PUSH_DATA_TYPE::BackgroundAlphaValue)
    {
        floatptr = get_dev_data_ptr()->reg_rsp_alpha_valt;
    }
    else if (type == PUSH_DATA_TYPE::BackgroundBetaValue)
    {
        floatptr = get_dev_data_ptr()->reg_rsp_bate_valt;
    }
    else if (type == PUSH_DATA_TYPE::BackgroundGammaValue)
    {
        floatptr = get_dev_data_ptr()->reg_rsp_gama_valt;
    }
    else
    {
        return 1;
    }

    for (int i = 0; i < get_dev_data_ptr()->reg_rsp_num; i++)
    {
        msb_push_float_to_array(data, floatptr[i]);
    }
    // 1.addr
    msb_push_u8_to_array(packet, modbus_rtu_slave_addr);
    // 2.op
    msb_push_u8_to_array(packet, OPS::READ);
    // 3. data len
    msb_push_u8_to_array(packet, static_cast<uint16_t>(data.size()));
    packet.insert(packet.end(), data.begin(), data.end());
    // 4.crc
    uint16_t crc = modbus_crc16(packet.data(), packet.size());
    lsb_push_u16_to_array(packet, crc);
    return 0;
}
uint32_t modbus_rtu::create_modbus_rtu_packet_rsp_others(vector<uint8_t> &packet)
{

    packet.clear();
    vector<uint8_t> data;
    msb_push_u16_to_array(data, static_cast<uint16_t>(PUSH_DATA_TYPE::MeasurementOthers));

    msb_push_u32_to_array(data, get_dev_data_ptr()->reg_alarm_count);
    msb_push_u32_to_array(data, get_dev_data_ptr()->reg_test_count);
    msb_push_u32_to_array(data, get_dev_data_ptr()->reg_status);
    for (int i = 0; i < 6; i++)
    {
        msb_push_u16_to_array(data, get_dev_data_ptr()->reg_rtc_time[i]);
    }
    msb_push_array_to_array(data, (uint8_t *)get_dev_data_ptr()->reg_read_person_id, 20);

    // 1.addr
    msb_push_u8_to_array(packet, modbus_rtu_slave_addr);
    // 2.op
    msb_push_u8_to_array(packet, OPS::READ);
    // 3. data len
    msb_push_u8_to_array(packet, static_cast<uint16_t>(data.size()));
    packet.insert(packet.end(), data.begin(), data.end());
    // 4.crc
    uint16_t crc = modbus_crc16(packet.data(), packet.size());
    lsb_push_u16_to_array(packet, crc);
    return 0;
}

void modbus_rtu::modbus_rtu_thread_func()
{
    modbus_rtu_thread_exit = false;
    while (!modbus_rtu_thread_exit)
    {
        EVENT event;
        packet.clear();
        if (get_send_modbusrtu_queue_ptr()->try_pop(event))
        {
            zlog_info(modbus_rtu_category, "modbus_rtu_thread_func event %08x", event);
            // 处理事件
            switch (event)
            {
            case EVENT::RSP_DATA_BASE_STATUS:
            {
                create_modbus_rtu_packet_rsp_status(packet);

                break;
            }
            case EVENT::RSP_DATA_BASE_ALPHA:
            {
                create_modbus_rtu_packet_rsp_data(packet, PUSH_DATA_TYPE::BackgroundAlphaValue);
                break;
            }
            case EVENT::RSP_DATA_BASE_BETA:
            {
                create_modbus_rtu_packet_rsp_data(packet, PUSH_DATA_TYPE::BackgroundBetaValue);
                break;
            }
            case EVENT::RSP_DATA_BASE_GAMA:
            {
                create_modbus_rtu_packet_rsp_data(packet, PUSH_DATA_TYPE::BackgroundGammaValue);
                break;
            }
            case EVENT::RSP_DATA_BASE_OTHERS:
            {
                create_modbus_rtu_packet_rsp_others(packet);
                break;
            }

            default:
                break;
            }
        }
        if (packet.size() > 0)
        {
            hzlog_info(modbus_rtu_category, packet.data(), packet.size());
            modbus_rtu_serial_app->send_byte(packet.data(), packet.size());
        }
        usleep(1000 * 10);
    }
}
void modbus_rtu::set_stop_rtu_thread()
{
    modbus_rtu_thread_exit = true;
}

void modbus_rtu::wait_rtu_thread_stop()
{
    modbus_rtu_thread->join();
}